package com.nageoffer.jobtrain.projects.common.biz.user;

import com.alibaba.fastjson2.JSON;
import com.alibaba.nacos.shaded.com.google.common.collect.Lists;
import com.nageoffer.jobtrain.common.web.errorcode.BaseErrorCode;
import com.nageoffer.jobtrain.common.web.result.Results;
import com.nageoffer.jobtrain.projects.common.constant.RedisCacheConstant;
import com.nageoffer.jobtrain.projects.toolkit.HttpServletUtils;
import jakarta.servlet.*;
import jakarta.servlet.http.HttpServletRequest;
import jakarta.servlet.http.HttpServletResponse;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.data.redis.core.StringRedisTemplate;

import java.io.IOException;
import java.io.PrintWriter;
import java.util.List;
import java.util.concurrent.TimeUnit;

/**
 * 防止短信盗刷过滤器
 * author：唐晨
 */
@Slf4j
@RequiredArgsConstructor
public class PreventSmsSkimFilter implements Filter {
    private final StringRedisTemplate stringRedisTemplate;
    // 每天最多请求验证码次数
    private static final int MAX_REQUESTS_PER_DAY = 10;

    private static final List<String> UN_IGNORE_URI = Lists.newArrayList(
            "/api/job-train/project/user/send-message"         // 用户登录发送验证码
    );

    @Override
    public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain) throws IOException, ServletException {
        // 如果这个请求是申请登录验证码才走这个请求，否则直接走下一个过滤器链
        String requestUri = ((HttpServletRequest) servletRequest).getRequestURI();
        if (UN_IGNORE_URI.contains(requestUri)) {
            String ipAddress = HttpServletUtils.getIPAddress((HttpServletRequest) servletRequest).replace(":", ".");
            // 获取IP缓存次数
            String requestCountStr = stringRedisTemplate.opsForValue().get(RedisCacheConstant.PREVENT_SMS_SKIM_KEY + ipAddress);
            int requestCount = (requestCountStr != null) ? Integer.parseInt(requestCountStr) : 0;
            if (requestCount >= MAX_REQUESTS_PER_DAY) {
                log.error("IP 地址 {} 请求超过次数限制，每天最多请求 {} 次", ipAddress, MAX_REQUESTS_PER_DAY);
                returnJson((HttpServletResponse) servletResponse, JSON.toJSONString(Results.failure(BaseErrorCode.USER_SMS_SEND_MESSAGE_FAIL)));
                return;
            }
            // 如果没有超过最大请求次数，更新 Redis中的请求次数,继续执行请求 -设置过期时间为 24 小时
            stringRedisTemplate.opsForValue().set(RedisCacheConstant.PREVENT_SMS_SKIM_KEY + ipAddress,
                    String.valueOf(requestCount + 1), 1, TimeUnit.DAYS);
        }
        filterChain.doFilter(servletRequest, servletResponse);
    }

    // 返回 JSON 格式的错误信息并设置 HTTP 状态码
    private void returnJson(HttpServletResponse response, String json) throws IOException {
        response.setCharacterEncoding("utf-8");
        response.setContentType("application/json; charset=utf-8");
        try (PrintWriter writer = response.getWriter()) {
            writer.println(json);
        }
    }
}
